/*
 * Copyright (C) 2012-2013  Romain DUBOIS
 * 
 * This file is part of NeMoS - Network and Modular Software
 * 
 * NeMoS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * NeMoS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with NeMoS.  If not, see <http://www.gnu.org/licenses/>.
 */
package nemos.swing.internal;

import java.awt.Component;
import java.awt.Window;
import java.util.Collection;

import nemos.launch.progress.IProgressListener;
import nemos.launch.progress.IRecords;
import nemos.launch.progress.IStatus;
import nemos.swing.IComponentFactory;
import nemos.util.log.NemosLogger;
import nemos.util.osgi.FilterBuilder;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;

/**
 * Launcher : The swing launcher class.
 * 
 * <p>
 * This class waits for the framework launch to ends and then generates and
 * displays a target component.
 * </p>
 * 
 * @author Romain DUBOIS
 */
@Service(IProgressListener.class)
@org.apache.felix.scr.annotations.Component(name = "nemos.swing.Launcher")
public class Launcher implements IProgressListener {

    /** The initial component name property name */
    private static final String INIT_COMPONENT = "nemos.swing.init"; //$NON-NLS-1$
    /** The initial component properties property name */
    private static final String INIT_COMPONENT_PROPERTIES = "nemos.swing.initProps"; //$NON-NLS-1$
    /**
     * The name of the property which indicates if a component creation is
     * required
     */
    private static final String REQUIRED = "nemos.swing.init.required"; //$NON-NLS-1$

    /** This component context */
    private ComponentContext mContext;
    /** The logger */
    private NemosLogger mLogger;

    /** The component name */
    private String mComponent;
    /** The component properties */
    private String mProperties;
    /** The required flag */
    private boolean mRequired;

    /**
     * Constructor.
     */
    public Launcher() {
        super();
    }

    /**
     * Start the launcher.
     * 
     * @param pContext
     *            The context of this DS component
     */
    @Activate
    public void start(final ComponentContext pContext) {
        mContext = pContext;
        mLogger = new NemosLogger(Launcher.class);
        mLogger.setServiceReference(pContext.getServiceReference());

        mComponent = pContext.getBundleContext().getProperty(INIT_COMPONENT);
        mProperties = pContext.getBundleContext().getProperty(INIT_COMPONENT_PROPERTIES);
        mRequired = Boolean.parseBoolean(pContext.getBundleContext().getProperty(REQUIRED));
    }

    /**
     * {@inheritDoc}
     * 
     * @see nemos.launch.progress.IProgressListener#ended()
     */
    @Override
    public void ended() {
        final BundleContext lContext = mContext.getBundleContext();

        try {
            // Try to get a service reference
            mLogger.debug(SwingMessage.LAUNCH_FACTORY_SEARCHING, mComponent);
            final String lFilter = FilterBuilder.getStringFilter(IComponentFactory.COMPONENT_TYPE,
                    mComponent);
            final Collection<ServiceReference<IComponentFactory>> lRefs = lContext
                    .getServiceReferences(IComponentFactory.class, lFilter);
            ServiceReference<IComponentFactory> lRef = null;
            if (!lRefs.isEmpty()) {
                lRef = lRefs.iterator().next();
                mLogger.debug(lRef, SwingMessage.LAUNCH_FACTORY_REF_FOUND);
            }

            // Try to get the service
            IComponentFactory lFactory = null;
            if (lRef != null) {
                lFactory = lContext.getService(lRef);
            }

            // Try to create the component
            Component lComponent = null;
            if (lFactory == null) {
                mLogger.debug(SwingMessage.LAUNCH_FACTORY_MISSING);
            } else {
                mLogger.debug(SwingMessage.LAUNCH_FACTORY_FOUND);
                try {
                    if (mProperties == null) {
                        mLogger.debug(SwingMessage.LAUNCH_COMPONENT_INIT);
                        lComponent = lFactory.createComponent();
                    } else {
                        mLogger.debug(SwingMessage.LAUNCH_COMPONENT_INIT_WITH_PROPS, mProperties);
                        lComponent = lFactory.createComponent(mProperties);
                    }
                } finally {
                    lContext.ungetService(lRef);
                }
            }

            // Display the component
            if (lComponent == null || !(lComponent instanceof Window)) {

                if (lComponent == null && lFactory != null) {
                    mLogger.warn(SwingMessage.LAUNCH_COMPONENT_MISSING, mComponent);
                } else if (lComponent != null) {
                    mLogger.warn(SwingMessage.LAUNCH_COMPONENT_INVALID, mComponent, lComponent
                            .getClass().getSimpleName());
                }

                // Shutdown framework if the init component was required
                if (mRequired) {
                    mLogger.info(SwingMessage.LAUNCH_SHUTDOWN);
                    try {
                        lContext.getBundle(0).stop();
                    } catch (final BundleException e) {
                        mLogger.error(SwingMessage.LAUNCH_SHUTDOWN_FAILED, e);
                    }
                }
            } else {
                mLogger.info(SwingMessage.LAUNCH_COMPONENT_DISPLAY);
                lComponent.setVisible(true);
            }

        } catch (final InvalidSyntaxException e) {
            mLogger.error(SwingMessage.INTERNAL_ERROR, e);
        }

        // No need of the launcher component anymore
        mContext.getComponentInstance().dispose();
        mLogger.debug(SwingMessage.LAUNCH_DISPOSE);
    }

    /**
     * {@inheritDoc}
     * 
     * @see nemos.launch.progress.IProgressListener#init(nemos.launch.progress.IRecords,
     *      int)
     */
    @SuppressWarnings("unused")
    @Override
    public void init(final IRecords pRecords, final int pTargetLevel) {
        // Nothing to do
    }

    /**
     * {@inheritDoc}
     * 
     * @see nemos.launch.progress.IProgressListener#progressChanged(nemos.launch.progress.IStatus)
     */
    @SuppressWarnings("unused")
    @Override
    public void progressChanged(final IStatus pStatus) {
        // Nothing to do
    }
}
